package program.services;

import program.domain.PCB;
import program.utils.PCBQueue;
import java.util.ArrayList;


/**
 * The type Round robin.
 *
 * @program: OSAlgorithms
 * @description: 时间片轮转调度算法
 * @author: W
 * @create: 2021 -10-21 17:24
 */
public class RoundRobin {
    /**
     * 当前时间
     */
    private int time = 0;

    private PCBQueue readyQueue = new PCBQueue();

    private PCBQueue runningQueue = new PCBQueue();

    private PCBQueue finishedQueue = new PCBQueue();

    /**
     * The Processes.
     */
    public ArrayList<PCB> processes = new ArrayList<>();

    /**
     * 所有进程数量
     */
    private int size;

    /**
     * Gets time.
     *
     * @return the time
     */
    public int getTime() {
        return time;
    }

    /**
     * Sets time.
     *
     * @param time the time
     */
    public void setTime(int time) {
        this.time = time;
    }

    /**
     * Gets ready queue.
     *
     * @return the ready queue
     */
    public PCBQueue getReadyQueue() {
        return readyQueue;
    }

    /**
     * Sets ready queue.
     *
     * @param readyQueue the ready queue
     */
    public void setReadyQueue(PCBQueue readyQueue) {
        this.readyQueue = readyQueue;
    }

    /**
     * Gets running queue.
     *
     * @return the running queue
     */
    public PCBQueue getRunningQueue() {
        return runningQueue;
    }

    /**
     * Sets running queue.
     *
     * @param runningQueue the running queue
     */
    public void setRunningQueue(PCBQueue runningQueue) {
        this.runningQueue = runningQueue;
    }

    /**
     * Gets finished queue.
     *
     * @return the finished queue
     */
    public PCBQueue getFinishedQueue() {
        return finishedQueue;
    }

    /**
     * Sets finished queue.
     *
     * @param finishedQueue the finished queue
     */
    public void setFinishedQueue(PCBQueue finishedQueue) {
        this.finishedQueue = finishedQueue;
    }

    /**
     * Gets processes.
     *
     * @return the processes
     */
    public ArrayList<PCB> getProcesses() {
        return processes;
    }

    /**
     * Sets processes.
     *
     * @param processes the processes
     */
    public void setProcesses(ArrayList<PCB> processes) {
        this.processes = processes;
    }

    /**
     * Gets size.
     *
     * @return the size
     */
    public int getSize() {
        return size;
    }

    /**
     * Sets size.
     *
     * @param size the size
     */
    public void setSize(int size) {
        this.size = size;
    }

    /**
     * Scheduling.
     */
    public void scheduling() {

        while (!readyQueue.isEmpty()) {
            //就绪队列出队
            PCB readyOut = readyQueue.remove();

            //运行队列入队
            runningQueue.add(readyOut);
            readyOut.setState("运行");

            try {
                System.out.println("进程" + readyOut.getPid() + "开始执行,进程总时间:" + readyOut.getCpuTime() + "ms  完成剩余时间:" + readyOut.getNeedTime() + "ms  分配时间片:" + readyOut.getRound() + "ms");
                int count = readyOut.getCount();
                count++;
                readyOut.setCount(count);
                int needTime = readyOut.getNeedTime() - readyOut.getRound();
                Thread.sleep(readyOut.getRound());
                readyOut.setNeedTime(needTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("进程" + readyOut.getPid() + "的时间片结束了," + "完成剩余时间:" + readyOut.getNeedTime() + "ms");


            //运行队列出队
            PCB runOut = runningQueue.remove();
            if (runOut.getNeedTime() <= 0) {
                //该进程运行结束
                System.out.println("进程" + readyOut.getPid() + "已全部运行结束,共使用" + readyOut.getCount() + "次cpu时间片");
                runOut.setState("结束");
                finishedQueue.add(runOut);
            }
            else {
                //未结束，重新进入就绪队列
                System.out.println("进程" + readyOut.getPid() + "重新进入就绪队列，完成剩余时间:" + readyOut.getNeedTime() + "ms");
                runOut.setState("就绪");
                readyQueue.add(runOut);
            }

            System.out.println(" ");

        }
    }

    /**
     * 调度准备队列
     */
    public void scheduleReady() {
        if (!processes.isEmpty()) {
            while (processes.get(0).getArriveTime() <= time) {
                PCB pcb = processes.get(0);
                pcb.setState("就绪");
                readyQueue.add(pcb);
                System.out.println("进程" + pcb.getPid() + "进入就绪队列");
                processes.remove(0);
                if (processes.size() == 0) {
                    break;
                }
            }
        }
    }

    /**
     * 调度运行队列
     */
    public void scheduleRunning() {
        time += 1;
        if (runningQueue.isEmpty() && readyQueue.peek() != null) {
            //cpu空闲
            System.out.println("cpu空闲");
            PCB pcb = readyQueue.remove();
            pcb.setState("运行");
            System.out.println("进程" + pcb.getPid() + "开始执行");
            runningQueue.add(pcb);
        }

    }

    /**
     * 进程运行
     */
    public void processRunning() {
        if (!runningQueue.isEmpty()) {
            //cpu执行进程中,改变剩余时间
            PCB pcb = runningQueue.peek();
            int count = pcb.getCount() + 1;
            pcb.setCount(count);
            int needTime = pcb.getNeedTime() - 1;
            pcb.setNeedTime(needTime);
        }
    }

    /**
     * 进行时间片轮转
     */
    public void scheduleRound() {
        if (runningQueue.peek() != null) {
            if (runningQueue.peek().getNeedTime() != 0 && size!=finishedQueue.getSize()+1) {
                PCB pcb = runningQueue.remove();
                //结束时间片
                pcb.setState("就绪");
                readyQueue.add(pcb);
                System.out.println("进程" + pcb.getPid() + "再次进入就绪队列");
            }
        }
    }

    /**
     * 调度完成队列
     */
    public void scheduleFinish() {
        if (runningQueue.peek() != null) {
            if (runningQueue.peek().getNeedTime() == 0) {
                PCB pcb = runningQueue.remove();
                //运行结束
                runningQueue.remove();
                pcb.setState("结束");
                System.out.println("进程" + pcb.getPid() + "已执行完毕，耗时：" + pcb.getCpuTime() + "ms");
                finishedQueue.add(pcb);
            }
        }
    }

}
